using System;
using C3.XNA;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using RpgXna.Model.Entities;
using RpgXna.Model.Entities.MainCharacter;
using RpgXna.Model.Helpers;
using RpgXna.Model.Interfaces.InterfacesManagement;
using RpgXna.Model.Interfaces.Inventory.NavigationBehaviors;
using RpgXna.Model.XnaClassesWrappers;

namespace RpgXna.Model.Interfaces.Inventory
{
    public class Inventory : IInterface
    {
        private readonly IInterfaceComponent _interface;
        private readonly Slot[,] _inventory;
        private readonly int _xs;
        private readonly int _ys;
        private Vector2 _cs;
        private Rectangle _holder;
        private InventoryInteractBehavior _interact;
        private InventoryNavigationBehavior _nav;
        private Slot _selectedSlot;
        private InventoryShowHideBehavior _showHide;

        public Inventory(IInterfaceComponent ifc, GraphicsDeviceManager graphics, IInputManager input)
        {
            Interactions = new InteractionEventWrapper();
            _interface = ifc;
            _inventory = new Slot[10, 10];

            _xs = _inventory.GetLength(0);
            _ys = _inventory.GetLength(1);

            CreateSlots();
            _cs = new Vector2((float)graphics.GraphicsDevice.Viewport.Width / 2,
                              (float)graphics.GraphicsDevice.Viewport.Height / 2);

            input.RightMouseButtonClick += InputRightMouseButtonClick;

            CreateNavigationBehaviors();
        }

        public InteractionEventWrapper Interactions { get; private set; }

        public bool Add(PickableObject o)
        {
            Slot s = ReturnFirstAvailableSlot();
            if (s != null)
            {
                s.Item = o;
                return true;
            }
            return false;
        }

        public void Draw(SpriteBatch sb)
        {
            if (!_interface.IsVisible) return;

            sb.FillRectangle(_holder, Color.Black);

            IterateSlots((slot) =>
                             {
                                 if (!slot.IsFree)
                                 {
                                     sb.Draw(slot.Item.TextureMin, slot.Box, Color.White);
                                 }

                                 if (slot.IsSelected)
                                 {
                                     sb.DrawRectangle(slot.Box, Color.Red, 2);
                                 }
                                 else
                                 {
                                     sb.DrawRectangle(slot.Box, Color.White);
                                 }
                             });
        }

        public void Remove(PickableObject o)
        {
            IterateSlots((slot) =>
                             {
                                 if (!slot.IsFree && slot.Item == o)
                                 {
                                     slot.Item = null;
                                 }
                             });
        }

        public void Update(IKeyboardStateWrapper kbs)
        {
            _interact.Execute(kbs);

            _selectedSlot = _nav.Execute(_inventory, kbs, _selectedSlot);

            _showHide.Execute(kbs);

            UpdateHolders();
        }

        private bool CanDoActions()
        {
            return _interface.IsVisible;
        }

        private bool CanInteractWithSlot()
        {
            return CanDoActions() && _selectedSlot != null && !_selectedSlot.IsFree;
        }

        private void CreateNavigationBehaviors()
        {
            _nav = new InventoryNavigationBehavior(CanDoActions);
            _showHide = new InventoryShowHideBehavior(() => true, ShowHideInterface);
            _interact = new InventoryInteractBehavior(CanInteractWithSlot, InteractObject);
        }
        private void CreateSlots()
        {
            for (int x = 0; x < _xs; x++)
            {
                for (int y = 0; y < _ys; y++)
                {
                    _inventory[x, y] = new Slot(x, y);
                }
            }
            _inventory[0, 0].IsSelected = true;
            _selectedSlot = _inventory[0, 0];
        }

        private void InputRightMouseButtonClick(MouseState state)
        {
            if (!_interface.IsVisible) return;
            IterateSlots((slot) =>
                             {
                                 if (slot.Box.Contains(state.X, state.Y) && !slot.IsFree)
                                 {
                                     Interactions.OnInteract(slot.Position, slot.Item);
                                 }
                             });
        }

        private void InteractObject()
        {
            Interactions.OnInteract(_selectedSlot.Position, _selectedSlot.Item);
        }
        private void IterateSlots(Action<Slot> iter)
        {
            for (int x = 0; x < _xs; x++)
            {
                for (int y = 0; y < _ys; y++)
                {
                    Slot slot = _inventory[x, y];
                    iter(slot);
                }
            }
        }

        private Slot ReturnFirstAvailableSlot()
        {
            for (int x = 0; x < _xs; x++)
            {
                for (int y = 0; y < _ys; y++)
                {
                    Slot slot = _inventory[x, y];
                    if (slot.IsFree)
                        return slot;
                }
            }
            return null;
        }

        private void ShowHideInterface()
        {
            if (_interface.IsVisible)
            {
                Hide();
                return;
            }
            Show();
        }

        private void UpdateHolders()
        {
            //calcultate inventory and slot holders rectangles
            int width = (_xs - 1) * 50;
            int height = (_ys - 1) * 50;
            _holder = new Rectangle((int)(_cs.X - 300), (int)(_cs.Y - 250), width + 5, height + 5);

            IterateSlots((slot) =>
                             {
                                 var slotPos = new Vector2(_holder.X + (slot.X * 45) + 5,
                                                           _holder.Y + (slot.Y * 45) + 5);
                                 var rect = new Rectangle((int)slotPos.X, (int)slotPos.Y, 40, 40);
                                 slot.Box = rect;
                             });
        }

        public bool IsVisible
        {
            get { return _interface.IsVisible; }
        }

        public int Priority
        {
            get { return _interface.Priority; }
        }

        public void Show()
        {
            _interface.Show();
        }

        public void Hide()
        {
            _interface.Hide();
        }
    }
}